package com.ts.comm;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;

/**
 * 日期常用工具类
 * Created by xhc on 2017-3-22.
 */
public class SysDate {
    private static String[] JQ_Holidays = {"清明\t清明节"};
    private static String[] CN_Holidays = {"正月初一\t春节", "正月十五\t元宵节", "五月初五\t端午节", "八月十五\t中秋节", "九月初九\t重阳节"};//农历节日
    private static String[] EN_Holidays = {
            "01-01\t元旦", "02-14\t情人节", "03-08\t妇女节", "05-01\t劳动节", "06-01\t儿童节"
            , "08-01\t建党节", "08-01\t建军节", "09-10\t教师节", "10-01\t国庆节", "12-25\t圣诞节"
    };//公历节日

    private static String[] CHINA_JIEQI = {
            "小寒", "大寒", "立春", "雨水", "惊蛰", "春分"
            , "清明", "谷雨", "立夏", "小满", "芒种", "夏至"
            , "小暑", "大暑", "立秋", "处暑", "白露", "秋分"
            , "寒露", "霜降", "立冬", "小雪", "大雪", "冬至"
    };
    private static String[] CHINA_DAY = {"*"
            , "初一", "初二", "初三", "初四", "初五"
            , "初六", "初七", "初八", "初九", "初十"
            , "十一", "十二", "十三", "十四", "十五"
            , "十六", "十七", "十八", "十九", "二十"
            , "廿一", "廿二", "廿三", "廿四", "廿五"
            , "廿六", "廿七", "廿八", "廿九", "三十"};
    private static String[] CHINA_MONTH = {"*", "正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "冬", "腊"};
    private static int[] LunarCalendarTable = {
            0x04AE53, 0x0A5748, 0x5526BD, 0x0D2650, 0x0D9544, 0x46AAB9, 0x056A4D, 0x09AD42, 0x24AEB6, 0x04AE4A,/*1901-1910*/
            0x6A4DBE, 0x0A4D52, 0x0D2546, 0x5D52BA, 0x0B544E, 0x0D6A43, 0x296D37, 0x095B4B, 0x749BC1, 0x049754,/*1911-1920*/
            0x0A4B48, 0x5B25BC, 0x06A550, 0x06D445, 0x4ADAB8, 0x02B64D, 0x095742, 0x2497B7, 0x04974A, 0x664B3E,/*1921-1930*/
            0x0D4A51, 0x0EA546, 0x56D4BA, 0x05AD4E, 0x02B644, 0x393738, 0x092E4B, 0x7C96BF, 0x0C9553, 0x0D4A48,/*1931-1940*/
            0x6DA53B, 0x0B554F, 0x056A45, 0x4AADB9, 0x025D4D, 0x092D42, 0x2C95B6, 0x0A954A, 0x7B4ABD, 0x06CA51,/*1941-1950*/
            0x0B5546, 0x555ABB, 0x04DA4E, 0x0A5B43, 0x352BB8, 0x052B4C, 0x8A953F, 0x0E9552, 0x06AA48, 0x6AD53C,/*1951-1960*/
            0x0AB54F, 0x04B645, 0x4A5739, 0x0A574D, 0x052642, 0x3E9335, 0x0D9549, 0x75AABE, 0x056A51, 0x096D46,/*1961-1970*/
            0x54AEBB, 0x04AD4F, 0x0A4D43, 0x4D26B7, 0x0D254B, 0x8D52BF, 0x0B5452, 0x0B6A47, 0x696D3C, 0x095B50,/*1971-1980*/
            0x049B45, 0x4A4BB9, 0x0A4B4D, 0xAB25C2, 0x06A554, 0x06D449, 0x6ADA3D, 0x0AB651, 0x093746, 0x5497BB,/*1981-1990*/
            0x04974F, 0x064B44, 0x36A537, 0x0EA54A, 0x86B2BF, 0x05AC53, 0x0AB647, 0x5936BC, 0x092E50, 0x0C9645,/*1991-2000*/
            0x4D4AB8, 0x0D4A4C, 0x0DA541, 0x25AAB6, 0x056A49, 0x7AADBD, 0x025D52, 0x092D47, 0x5C95BA, 0x0A954E,/*2001-2010*/
            0x0B4A43, 0x4B5537, 0x0AD54A, 0x955ABF, 0x04BA53, 0x0A5B48, 0x652BBC, 0x052B50, 0x0A9345, 0x474AB9,/*2011-2020*/
            0x06AA4C, 0x0AD541, 0x24DAB6, 0x04B64A, 0x69573D, 0x0A4E51, 0x0D2646, 0x5E933A, 0x0D534D, 0x05AA43,/*2021-2030*/
            0x36B537, 0x096D4B, 0xB4AEBF, 0x04AD53, 0x0A4D48, 0x6D25BC, 0x0D254F, 0x0D5244, 0x5DAA38, 0x0B5A4C,/*2031-2040*/
            0x056D41, 0x24ADB6, 0x049B4A, 0x7A4BBE, 0x0A4B51, 0x0AA546, 0x5B52BA, 0x06D24E, 0x0ADA42, 0x355B37,/*2041-2050*/
            0x09374B, 0x8497C1, 0x049753, 0x064B48, 0x66A53C, 0x0EA54F, 0x06B244, 0x4AB638, 0x0AAE4C, 0x092E42,/*2051-2060*/
            0x3C9735, 0x0C9649, 0x7D4ABD, 0x0D4A51, 0x0DA545, 0x55AABA, 0x056A4E, 0x0A6D43, 0x452EB7, 0x052D4B,/*2061-2070*/
            0x8A95BF, 0x0A9553, 0x0B4A47, 0x6B553B, 0x0AD54F, 0x055A45, 0x4A5D38, 0x0A5B4C, 0x052B42, 0x3A93B6,/*2071-2080*/
            0x069349, 0x7729BD, 0x06AA51, 0x0AD546, 0x54DABA, 0x04B64E, 0x0A5743, 0x452738, 0x0D264A, 0x8E933E,/*2081-2090*/
            0x0D5252, 0x0DAA47, 0x66B53B, 0x056D4F, 0x04AE45, 0x4A4EB9, 0x0A4D4C, 0x0D1541, 0x2D92B5          /*2091-2099*/
    };

    private static String[] CHINA_WEEK = {"星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"};

    private static String[] mArrFormat = new String[]{"yyyy-MM-dd", "yyyy/MM/dd", "yyyy年MM月dd日", "yyyy\\MM\\dd",
            "MMM dd yyyy", "yyyy MMM d", "yyyy.MM.dd", "d MMM yyyy", "yyyy.MMM.dd", "yy-MM-dd", "yy/MM/dd",
            "yy年MM月dd日", "yy\\MM\\dd", "MMM dd yy", "yy MMM dd", "yy.MM.dd", "d MMM yy", "yy.MMM.dd"};

    /**
     * 方法说明：获得当前年月日 时分秒（yyyy-MM-dd HH:mm:ss）
     *
     * @return
     * @throw
     */
    public static String getNowDateTime() {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
    }

    /**
     * 获得当前时间，格式YYYY-MM-DD
     *
     * @return
     */
    public static String getNowDate() {
        SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        return mDateFormat.format(new Date());
    }

    /**
     * 获得当前年度，格式YYYY
     *
     * @return
     */
    public static String getNowYear() {
        return new SimpleDateFormat("yyyy").format(new Date());
    }

    /**
     * 获得当前时间
     *
     * @return 返回格式 12:12:30
     */
    public static String getNowTime() {
        return new SimpleDateFormat("HH:mm:ss").format(new Date());
    }

    /**
     * 字符串日期转换为date
     *
     * @param sDate 日期字符串（支持常用格式）
     * @return
     */
    public static Date stringToDate(String sDate) {
        SimpleDateFormat sdf = new SimpleDateFormat();
        Date dRet = null;

        for (int i = 0; i < mArrFormat.length; i++) {
            try {
                sdf.applyPattern(mArrFormat[i]);
                dRet = sdf.parse(sDate);
            } catch (Exception e) {
                continue;
            }

            break;
        }

        return dRet;
    }

    /**
     * 获得年
     *
     * @param sDate
     * @return
     */
    public static int getYear(String sDate) {
        return Integer.parseInt(sDate.substring(0, 4));
    }

    /**
     * 获得月
     *
     * @param sDate
     * @return
     */
    public static int getMonth(String sDate) {
        return Integer.parseInt(sDate.substring(5, 7));
    }

    /**
     * 获得天
     *
     * @param sDate
     * @return
     */
    public static int getDay(String sDate) {
        return Integer.parseInt(sDate.substring(8, 10));
    }

    /**
     * 添加年度
     *
     * @param sDate
     * @param iYear 支持负数
     * @return
     */
    public static String addYear(String sDate, int iYear) {
        Date d = stringToDate(sDate);
        Calendar c = Calendar.getInstance();
        c.setTime(d);
        c.add(Calendar.YEAR, iYear);
        return new SimpleDateFormat("yyyy-MM-dd").format(c.getTime());
    }

    /**
     * 添加月份
     *
     * @param sDate
     * @param iMonth 支持负数
     * @return
     */
    public static String addMonth(String sDate, int iMonth) {
        Date d = stringToDate(sDate);
        Calendar c = Calendar.getInstance();
        c.setTime(d);
        c.add(Calendar.MONTH, iMonth);
        return new SimpleDateFormat("yyyy-MM-dd").format(c.getTime());
    }

    /**
     * 添加天数
     *
     * @param sDate
     * @param iDay  支持负数
     * @return
     */
    public static String addDay(String sDate, int iDay) {
        Date d = stringToDate(sDate);
        Calendar c = Calendar.getInstance();
        c.setTime(d);
        c.add(Calendar.DATE, iDay);
        return new SimpleDateFormat("yyyy-MM-dd").format(c.getTime());
    }

    /**
     * 两个字符串日期相差的天数
     *
     * @param sBeg
     * @param sEnd
     * @return
     */
    public static int dayDiff(String sBeg, String sEnd) {
        Date dBeg = stringToDate(sBeg);
        Date dEnd = stringToDate(sEnd);
        return dayDiff(dBeg, dEnd);
    }

    /**
     * 两个日期相差的天数
     *
     * @param dBeg
     * @param dEnd
     * @return
     */
    public static int dayDiff(Date dBeg, Date dEnd) {
        if (dBeg == null || dEnd == null)
            return 0;

        int OneDayMilliseconds = 86400000;
        int iOffset = TimeZone.getDefault().getRawOffset();

        return (int) ((dEnd.getTime() - iOffset) / OneDayMilliseconds - (dBeg.getTime() - iOffset) / OneDayMilliseconds);
    }

    /**
     * 获得日期对应的周几
     *
     * @param sDate
     * @return
     */
    public static int getWeekDay(String sDate) {
        Date date = stringToDate(sDate);
        return getWeekDay(date);
    }

    /**
     * 获得日期对应的周几
     *
     * @param date
     * @return
     */
    public static int getWeekDay(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int iWeekDay = cal.get(Calendar.DAY_OF_WEEK) - 1;
        return iWeekDay == 0 ? 7 : iWeekDay;
    }

    /**
     * 计算节气
     */
    public static String getChinaJieQi(String sDate) {
        int diff = dayDiff("1900-01-01", sDate) + 2;
        int y = getYear(sDate) - 1900;
        double F = 0;
        for (int x = 0; x < CHINA_JIEQI.length; x++) {
            F = 365.242 * y + 6.2 + 15.22 * x - 1.9 * Math.sin(0.262 * x);
            if (diff == (int) Math.floor(F)) {
                return CHINA_JIEQI[x];
            }
        }
        return "";
    }

    /**
     * 计算节日
     */
    public static String getHoliday(String sDate) {
        String sDay = "";
        sDay = sDate.substring(5) + "\t";
        for (int i = 0; i < EN_Holidays.length; i++) {
            if (EN_Holidays[i].startsWith(sDay)) {
                return EN_Holidays[i].substring(sDay.length());
            }
        }

        sDay = getChinaDay(sDate, true) + "\t";
        for (int i = 0; i < CN_Holidays.length; i++) {
            if (CN_Holidays[i].startsWith(sDay)) {
                return CN_Holidays[i].substring(sDay.length());
            }
        }

        sDay = getChinaJieQi(sDate) + "\t";
        for (int i = 0; i < JQ_Holidays.length; i++) {
            if (JQ_Holidays[i].startsWith(sDay)) {
                return JQ_Holidays[i].substring(sDay.length());
            }
        }
        return "";
    }

    /**
     * 计算农历
     */
    public static String getChinaDay(String sDate) {
        return getChinaDay(sDate, false);
    }

    /**
     * 获得中文天
     *
     * @param sDate
     * @param bFullDay
     * @return
     */
    public static String getChinaDay(String sDate, boolean bFullDay) {
        int Spring_NY, Sun_NY, StaticDayCount;
        int index, flag;
        int year, month, day;


        boolean isRunYue = false; //是否闰月

        year = getYear(sDate);
        month = getMonth(sDate);
        day = getDay(sDate);

        //Spring_NY 记录春节离当年元旦的天数。
        //Sun_NY 记录阳历日离当年元旦的天数。

        if (((LunarCalendarTable[year - 1901] & 0x0060) >> 5) == 1)
            Spring_NY = (LunarCalendarTable[year - 1901] & 0x001F) - 1;
        else
            Spring_NY = (LunarCalendarTable[year - 1901] & 0x001F) - 1 + 31;

        Sun_NY = dayDiff(year + "-01-01", sDate);

        //StaticDayCount记录大小月的天数 29 或30
        //index 记录从哪个月开始来计算。
        //flag 是用来对闰月的特殊处理。
        //判断阳历日在春节前还是春节后

        if (Sun_NY >= Spring_NY)//阳历日在春节后（含春节那天）
        {
            Sun_NY -= Spring_NY;
            month = 1;
            index = 1;
            flag = 0;

            if ((LunarCalendarTable[year - 1901] & (0x80000 >> (index - 1))) == 0)
                StaticDayCount = 29;
            else
                StaticDayCount = 30;

            while (Sun_NY >= StaticDayCount) {
                Sun_NY -= StaticDayCount;
                index++;
                if (month == ((LunarCalendarTable[year - 1901] & 0xF00000) >> 20)) {
                    flag = ~flag;
                    if (flag == 0) {
                        month++;
                    } else if (Sun_NY < StaticDayCount) {
                        isRunYue = true;
                    }
                } else
                    month++;

                if ((LunarCalendarTable[year - 1901] & (0x80000 >> (index - 1))) == 0)
                    StaticDayCount = 29;
                else
                    StaticDayCount = 30;
            }
            day = Sun_NY + 1;
        } else//阳历日在春节前
        {
            Spring_NY -= Sun_NY;
            year--;
            month = 12;
            if (((LunarCalendarTable[year - 1901] & 0xF00000) >> 20) == 0)
                index = 12;
            else
                index = 13;

            flag = 0;

            if ((LunarCalendarTable[year - 1901] & (0x80000 >> (index - 1))) == 0)
                StaticDayCount = 29;
            else
                StaticDayCount = 30;

            while (Spring_NY > StaticDayCount) {
                Spring_NY -= StaticDayCount;
                index--;
                if (flag == 0) {
                    month--;
                } else if (Sun_NY < StaticDayCount) {
                    isRunYue = true;
                }
                if (month == ((LunarCalendarTable[year - 1901] & 0xF00000) >> 20))
                    flag = ~flag;

                if ((LunarCalendarTable[year - 1901] & (0x80000 >> (index - 1))) == 0)
                    StaticDayCount = 29;
                else
                    StaticDayCount = 30;
            }
            day = StaticDayCount - Spring_NY + 1;
        }

        if (bFullDay) {
            return (isRunYue ? "闰" : "") + CHINA_MONTH[month] + "月" + CHINA_DAY[day];
        } else if (day == 1) {
            return (isRunYue ? "闰" : "") + CHINA_MONTH[month] + "月";
        } else {
            return CHINA_DAY[day];
        }
    }
    /**
     * 得到n天之后是周几
     * @param iDay
     * @return
     */
    public static String getAfterDayWeek(int iDay) {

        Calendar canlendar = Calendar.getInstance(); // java.util包
        canlendar.add(Calendar.DATE, iDay); // 日期减 如果不够减会将月变动
        Date date = canlendar.getTime();

        SimpleDateFormat sdf = new SimpleDateFormat("E");
        String dateStr = sdf.format(date);

        return dateStr;
    }
    /**
     * 判断是否是周末
     *
     * @param sDate
     * @return
     */
    public static Boolean isWeekend(String sDate) {
        Boolean bFlag = false;
        Date date = stringToDate(sDate);
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        int iDayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
        if (iDayOfWeek == 1 || iDayOfWeek == 7) {
            bFlag = true;
        }
        return bFlag;
    }

    /**
     * 剔除周末，获取工作日的时间(增加天数)
     *
     * @param sDate
     * @return
     */
    public static String getWorkDate(String sDate, int iAddDays) {
        int i = 0;
        for (i = 0; i < iAddDays; i++) {
            if (isWeekend(sDate)) {
                sDate = addDay(sDate, 1);
                if (isWeekend(sDate)) {
                    sDate = addDay(sDate, 1);
                }
            }
            sDate = addDay(sDate, 1);
        }
        if (isWeekend(sDate)) {
            sDate = addDay(sDate, 1);
            if (isWeekend(sDate)) {
                sDate = addDay(sDate, 1);
            }
        }

        return sDate;
    }
}
